package com.hex.ds.hdrs.cron.service;

import com.hex.ds.hdrs.agent.service.AgentManager;
import com.hex.ds.hdrs.agent.service.AgentSession;
import com.hex.ds.hdrs.app.service.AppManager;
import com.hex.ds.hdrs.common.constant.Const;
import com.hex.ds.hdrs.common.utils.HdrsDateUtil;
import com.hex.ds.hdrs.cron.converter.ICronTaskConverter;
import com.hex.ds.hdrs.cron.po.CronTask;
import com.hex.ds.hdrs.cron.po.CronTaskDef;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;

/**
 * @Package: com.hex.ds.hdrs.cron.service
 * @ClassName CronService
 * @Description: 多线程跑定时任务
 * @Author: jd.chen
 * @Date 2021/7/8 17:58
 * @Version v1.0
 **/
@Slf4j
@Service
public class CronService {

	@Autowired
	private ThreadPoolTaskScheduler threadPoolTaskScheduler;

	@Autowired
	private CronTaskService cronTaskService;

	@Autowired
	private AppManager appManager;

	@Autowired
	private AgentManager agentManager;

	@Autowired
	private ICronTaskConverter cronTaskConverter;

	/**
	 * 存放任务定义数据的map 主键为pkId
	 */
	private Map<String, ScheduledFuture<?>> cronMap = new HashMap<>();

	/**
	 * @Method: add
	 * @Param: [cronTaskDef]
	 * @Return: boolean
	 * @Description： 添加到线程
	 * @Author： jd.chen
	 * @Date： 2021/7/8 17:58
	 * @Version： V1.0
	 */
	public boolean add(CronTaskDef cronTaskDef) {
		log.info("进入添加任务【CronService.add】参数cronTaskDef：{}" , cronTaskDef.toString());
		if (null != cronMap.get(cronTaskDef.getPkId())) {
			return false;
		}
		ScheduledFuture<?> schedule = threadPoolTaskScheduler.schedule(new CronExec(cronTaskDef, this),
				new CronTrigger(cronTaskDef.getCronExpress()));
		cronMap.put(cronTaskDef.getPkId(), schedule);
		return true;
	}
	/**
	 * @Method: stop
	 * @Param: [cronTaskDef]
	 * @Return: boolean
	 * @Description：从线程删除
	 * @Author： Lijinwei
	 * @Date： 2021/6/4 15:25
	 * @Version： V1.0
	 */
	public boolean stop(CronTaskDef cronTaskDef) {
		log.info("进入删除任务【TaskService.stop】参数cronTaskDef：{}" , cronTaskDef.toString());
		if (null == cronMap.get(cronTaskDef.getPkId())) {
			return false;
		}
		ScheduledFuture<?> scheduledFuture = cronMap.get(cronTaskDef.getPkId());
		scheduledFuture.cancel(true);
		cronMap.remove(cronTaskDef.getPkId());
		return true;
	}

	/**
	 * @Method: taskExec
	 * @Param: [cronTaskDef]
	 * @Return: java.lang.String
	 * @Description： 执行任务
	 * @Author： jd.chen
	 * @Date： 2021/7/8 17:57
	 * @Version： V1.0
	 */
	public String taskExec(CronTaskDef cronTaskDef) {
		if (Const.IS_VALID_DATE.equals(cronTaskDef.getIsValidDate())) {
			// 表示任务日期范围生效
			String taskStDate = cronTaskDef.getTaskStDate();
			String taskEndDate = cronTaskDef.getTaskEndDate();
			Date curDate = HdrsDateUtil.getCurrentDateNoTime();
			Date stDate = HdrsDateUtil.getDate(taskStDate);
			Date endDate = HdrsDateUtil.getDate(taskEndDate);
			if (curDate.before(stDate)) {
				// 当前时间在开始时间之前 ，不执行任务 也不从线程中删除
			} else {
				if (curDate.after(endDate)) {
					// 当前时间在结束时间之后 不执行任务 从线程中删除
					stop(cronTaskDef);
				} else {
					// 在时间范围里 执行任务
					exeTask(cronTaskDef);
				}
			}
		} else {
			// 执行任务
			exeTask(cronTaskDef);
		}
		return null;
	}

	/**
	 * @Method: exeTask
	 * @Param: [cronTaskDef]
	 * @Return: void
	 * @Description： 执行任务
	 * @Author： jd.chen
	 * @Date： 2021/7/8 17:58
	 * @Version： V1.0
	 */
	private void exeTask(CronTaskDef cronTaskDef) {
		try {
			CronTask cronTask = cronTaskConverter.toCronTask(cronTaskDef);
			cronTaskService.insertCronTask(cronTask);

			String appointAgentCode = cronTask.getAppointAgentCode();
			AgentSession agentSession;
			if(StringUtils.isEmpty(appointAgentCode)){
				agentSession = appManager.getRandomAgentSession(cronTask.getAppCode());
			}else{
				agentSession = agentManager.getAgentSession(appointAgentCode);
			}
			agentSession.sendCronToAgent(cronTask);
		} catch (Exception e) {
			log.error("定时任务执行出错: {}" , e.getMessage(), e);
		}
	}
}
